/*
 * Platzad
 * Copyright 2008 Shayne Riley
 *
 * This file is part of Platzad.
 *
 * Platzad is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Platzad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Platzad.  If not, see <http://www.gnu.org/licenses/>.
 *
 * To contact the authors on questions or issues regarding the license,
 * you may send an email to <shayner at gmail dot com> or write to
 * Shayne Riley / P.O. Box 1092 / McCook, NE 69001.
 */

#include "Control.h"
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>
#include <iostream>
#include "SDLDelegate.h" // Helps with starting sdl-based systems.
#include "InputEntry.h"

namespace pzdControl
{

Control& Control::getInstance()
{
	// Because it is static, the destructor is called automatically at the
	// end of the application or thread or something.
	static Control instance;

	return instance;
}

Control::Control()
{
    init();
}

Control::~Control()
{
    finalize();
}

void Control::finalize()
{
	using namespace std;

	// TODO If thread is active, kill it.

    cout << "Control subsystem shut down." << endl;
}

void Control::init()
{
	using namespace std;

	// Initialize SDL core and window if needed.
	if(!pzd::SDLDelegate::getInstance().needSDLWithWindow())
	{
		// Failure
		cerr << "SDL not able to initialize, display sub-system or "
			<< "window cannot initialize." << endl;
		return;
	}

	SDL_Thread *thread;
	thread = SDL_CreateThread(Control::controlThreadEntryPoint,
			static_cast<Control*>(this));

	cout << "Control initialized." << endl;
}

void Control::addInputHandler(InputHandler& handler)
{
	InputListener bob = InputListener(handler);
	inputList.push_back(bob);
}

void Control::removeInputHandler(InputHandler& handler)
{
	// Hey, guess what? More coding to do.
//	inputList.remove(handler);
}

int Control::controlThreadEntryPoint(void *data)
{
	using namespace std;

	Control *mThis = static_cast<Control*>(data);

	int quit_flag = 0;

	// Start the event loop. Keep reading events until there is an event error
	// or the quit flag is set.
	SDL_Event event;

	while(SDL_WaitEvent(&event) != 0 && quit_flag == 0)
	{
		switch(event.type)
		{
		case SDL_KEYDOWN:
			// If the user pressed Q or escape, exit.
			if(event.key.keysym.sym == SDLK_q
					|| event.key.keysym.sym == SDLK_ESCAPE)
			{
				cout << "User wants to leave." << endl;
				quit_flag = 1;
			}
		// Note: There is no break between SDL_KEYDOWN and SDL_KEYUP. Both
		// share the same code, so we will fall through.
		case SDL_KEYUP:
			for(list<InputListener>::iterator bob = mThis->inputList.begin();
				bob != mThis->inputList.end(); ++bob)
			{
				InputEntry george = InputEntry(event.key);
				(*bob).getHandler()(george);
			}
			break;
		case SDL_QUIT:
			// If the user clicked the close button, quit.
			cout << "Quit event. Adios." << endl;
			quit_flag = 1;
		}

		SDL_Delay(1); // Wait a small amount of time (1ms, but probably 10ms)
	}

	// Since the user wants to quit, we'll notify the rest of the program.
	for(list<InputListener>::iterator bob = mThis->inputList.begin();
		bob != mThis->inputList.end(); ++bob)
	{
		InputEntry george = InputEntry(InputEntry::QUIT, true);
		(*bob).getHandler()(george);
	}

	return 0;
}

} // namespace
